// ----------------------------------------------------------------------------
// diabindEnumSymbols.h
// DIA Enumerates symbols
// ----------------------------------------------------------------------------

#pragma once

// ----------------------------------------------------------------------------

#include "diabindSymbol.h"

// ----------------------------------------------------------------------------

namespace diabind
{

// ----------------------------------------------------------------------------

interface IEnumSymbols
{
    virtual ~IEnumSymbols() {}

    virtual LONG get_Count() = 0;
    virtual CSymbolPtr Item(DWORD index) = 0;
};
typedef boost::shared_ptr< IEnumSymbols > CEnumSymbolsPtr;

// ----------------------------------------------------------------------------

template< class DiaEnumSymbolsT >
class CEnumSymbolsImpl : public IEnumSymbols
{
    typedef _com_IIID< DiaEnumSymbolsT, &__uuidof(DiaEnumSymbolsT) > CIiid;
    typedef _com_ptr_t< CIiid > CImplPtr;
public:
    explicit CEnumSymbolsImpl(const CImplPtr &pEnumSymbols)
        : m_pEnumSymbols(pEnumSymbols)
    {
        HRESULT hResult = m_pEnumSymbols->get_Count(&m_nCount);
        if (S_OK != hResult)
            throw CException(hResult, "IDiaEnumSymbols::get_Count");
    }

    virtual LONG get_Count() override
    {
        return m_nCount;
    }

    virtual CSymbolPtr Item(DWORD index) override
    {
        if (index >= static_cast<DWORD>(m_nCount))
            throw CPyException(PyExc_IndexError, "index out of range");

        return ItemT(&DiaEnumSymbolsT::Item, "IDiaEnumSymbols::Item", index);
    }

protected:
    template< class DiaSymbolT >
    CSymbolPtr ItemT(
        HRESULT (STDMETHODCALLTYPE DiaEnumSymbolsT::*pMethod)(DWORD, DiaSymbolT **),
        const char *szMethodName,
        DWORD index
    )
    {
        _com_ptr_t< _com_IIID<DiaSymbolT, &__uuidof(DiaSymbolT)> > pSymbol;
        HRESULT hResult = (m_pEnumSymbols->*pMethod)(index, &pSymbol);
        if (S_OK != hResult)
            throw CException(hResult, szMethodName);

        return CSymbolPtr( new CSymbolImpl<DiaSymbolT>(pSymbol) );
    }

private:
    CImplPtr m_pEnumSymbols;
    LONG m_nCount;
};

// ----------------------------------------------------------------------------

template< class DiaSymbolT >
class CEnumSymbolsFromVector : public IEnumSymbols
{
public:
    typedef _com_IIID< DiaSymbolT, &__uuidof(DiaSymbolT) > CIiid;
    typedef _com_ptr_t< CIiid > CImplPtr;

    explicit CEnumSymbolsFromVector(std::vector<CImplPtr> &arrSymbols)
    {
        m_arrSymbols.swap(arrSymbols);
    }

    virtual LONG get_Count() override
    {
        return static_cast<LONG>(m_arrSymbols.size());
    }

    virtual CSymbolPtr Item(DWORD index) override
    {
        if (index >= static_cast<DWORD>(m_arrSymbols.size()))
            throw CPyException(PyExc_IndexError, "index out of range");

        return CSymbolPtr( new CSymbolImpl<DiaSymbolT>(m_arrSymbols[index]) );
    }

private:
    std::vector<CImplPtr> m_arrSymbols;
};

// ----------------------------------------------------------------------------

}   // namespace diabind

// ----------------------------------------------------------------------------

